#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <unistd.h>
#include <pthread.h>

#include "LockGuard.hpp"
#include "Thread.hpp"
#include "Task.hpp"

const int N = 5;

// 设计为单例模式
// 1、只能创建一次：提供一个getinstans方法如果第一次就创建，其他直接返回那个对象
// 2、懒汉模式：用的时候再创建，下次就不需要创建了。

template <class T>
class ThreadPool
{
private:
    // 封住构造
    ThreadPool(int num = N)
        : _num(num), _threads(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    //拷贝和赋值全都不允许
    ThreadPool(const ThreadPool<T>& tp) = delete;
    ThreadPool<T>& operator=(const ThreadPool<T>& tp) = delete;

private:
    void threadWait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void threadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    bool isEmpty()
    {
        return _tasks.empty();
    }

public:
    // 不能new就可以使用这个函数
    // 设计为静态函数
    static ThreadPool<T> *GetInstance()
    {
        // 只有刚开始初始化的时候会进入new
        // 这样双判断有效防止多个线程同时new
        // 同时也可以规避后期多次申请锁、解锁
        if (instance == nullptr)
        {
            //LockGuard lg(&_mutex);
            //应该使用另一把锁，因为操作的不是同一种资源！
            LockGuard lg(&instance_mutex);
            if (instance == nullptr)
            {

                instance = new ThreadPool<T>();
                // 第一次要初始化！启动！
                instance->init();
                instance->start();
            }
        }

        return instance;
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    // 添加任务
    void pushTask(const T &t)
    {
        LockGuard lg(&_mutex);

        _tasks.push(t);
        // 唤醒一下进程们
        threadWakeup();
    }

    // 弹出任务
    T popTask()
    {
        // 这个只在类内使用
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

    void init()
    {
        for (int i = 0; i < _num; i++)
        {
            //_func : threadRoutine
            //_args : this
            _threads.push_back(Thread(i, threadRoutine, this));
        }
    }

    void start()
    {
        for (auto &t : _threads)
        {
            t.run();
        }
    }

    static void threadRoutine(void *args)
    {
        // 自动释放资源，不用等待了
        //  pthread_detach(pthread_self());
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);
        T t;
        // tp->LockQueue();
        {
            LockGuard lg(&(tp->_mutex));

            while (tp->isEmpty())
            {
                tp->threadWait();
            }
            t = tp->popTask();
        }
        // tp->UnLockQueue();

        t();
        cout << "format : " << t.formatArg() << "result:" << t.formatRes() << endl;
    }

private:
    // 1.存储线程的容器
    std::vector<Thread> _threads;
    // 2.线程个数
    int _num;
    // 3.任务队列
    std::queue<T> _tasks;
    // 4.需要让线程在特定条件下等待，条件变量
    pthread_cond_t _cond;
    // 5.一把锁保证队列安全
    pthread_mutex_t _mutex;
    // 6.要让instance在整个程序的生命周期都存在，所以必须使用static
    static ThreadPool<T> *instance;
    // 7、一把锁保证初次加载对象的时候线程安全
    static pthread_mutex_t instance_mutex;
};

// 类外初始化静态的成员
template <class T>
ThreadPool<T> *ThreadPool<T>::instance = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::instance_mutex = PTHREAD_MUTEX_INITIALIZER;
